﻿using LuaInterface;
using System;
using System.Collections.Generic;
using System.Xml;
using UnityEngine;
using WWISE;
using YanhuaMMO;

public class WwiseManager :MonoBehaviour
{
    public static WwiseManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance)
        {
            DestroyImmediate(this);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(this);
    }
    private void Start()
    {
        Init();
    }

    public enum WwiseFlagEnum
    {
        All = 0,
        Music = 1,
        Sound = 2,
        Voice = 3,
    }
	//音乐
	public GameObject MusicListener;
    public GameObject MusicEmitter;

    //音效
    public GameObject SoundEmitter;

    //语音
    public GameObject VoiceEmitter;

    string audioSettingPath = "/Audio/GeneratedSoundBanks/";
    bool hotPathAdded = false;
    //public string WwiseSetBasePath;
    //public string WwiseAddBasePath;
    
    // 已加载 SoundBank
    private List<string> loadBankList = new List<string>();

    // 已注册 GameObj
    private List<int> registerGameObjList = new List<int>();

    // switch
    private Dictionary<string, List<string>> switchDic = new Dictionary<string, List<string>>();

    private LuaFunction loadBankLuaCallback;

    public void Init()
    {
        ClearAllLoadBankList();
        ClearAllRegisterGameObjList();
        //AddBasePath();
        imperativeLoadShoundBank();
        
        initDelay();
    }
    
    //默认必须加载的SoundBank
    private void imperativeLoadShoundBank()
    {
        LoadSoundBank("ui");
        LoadSoundBank("Login_Bank");
        //TODO临时处理
        LoadSoundBank("BGM_Soundbank");
        //LoadSoundBank("mus_events");
        //LoadSoundBank("mus_login_audio");
        LoadSoundBank("char");
        //LoadSoundBank("vo_ch");
        //LoadSoundBank("vo_jap");
        LoadSoundBank("ani"); 
    }


    private void initDelay()
    {
        AkAudioListener _musicAkAudioListener = MusicListener.GetComponent<AkAudioListener>();
        _musicAkAudioListener.SetIsDefaultListener(true);
        _musicAkAudioListener.listenerId = (int)WwiseFlagEnum.Music;
    }
    //执行Wwise后回调
    private void postEventCallback(object cookie,AkCallbackType type,AkCallbackInfo info)
    {
        //Debug.LogError("----");
    }




    //    public void SetBasePath()
    //    {
    //        WwiseSetBasePath = AkBasePathGetter.GetFullSoundBankPath();
    //        return;

    //        WwiseSetBasePath = "";
    //#if UNITY_EDITOR
    //        string _newPath = Application.streamingAssetsPath;
    //#else
    //        _newPath = Application.persistentDataPath;
    //#endif
    //        _newPath += audioSettingPath;

    //#if UNITY_ANDROID
    //        _newPath += "Android";
    //#elif UNITY_IOS || UNITY_IPHONE
    //         _newPath += "iOS";
    //#else
    //        _newPath += "Windows";
    //#endif
    //        WwiseSetBasePath = _newPath+"/";
    //        AKRESULT _result = AkSoundEngine.SetBasePath(WwiseSetBasePath);
    //        if (_result != AKRESULT.AK_Success)
    //        {
    //            Debug.LogErrorFormat("Wwise:不存在此WwiseSetBasePath音频路径 {0}", WwiseSetBasePath);
    //            return;
    //        }
    //    }

    //    //热更加载路径
    public void AddBasePath()
    {
        this.gameObject.GetComponent<AkInitializer>().InitializationSettings = AkWwiseInitializationSettings.Instance;

        string basePath = "";
#if UNITY_EDITOR || UNITY_STANDALONE_WIN
        basePath = "file://" + Application.dataPath + "/StreamingAssets/";
#elif UNITY_ANDROID
        basePath = "jar:file://" + Application.dataPath + "!/assets/";
#elif UNITY_IPHONE
        basePath = Application.dataPath + "/Raw/";
#else
        basePath = "";
#endif

        basePath = basePath + "Audio/GeneratedSoundBanks/" + AkBasePathGetter.GetPlatformName();
        AkSoundEngine.SetBasePath(basePath);

        string _newPath = Util.DataPath + "Audio/GeneratedSoundBanks/" + AkBasePathGetter.GetPlatformName();

        AKRESULT _result = AkSoundEngine.AddBasePath(_newPath);
        if (_result == AKRESULT.AK_Success)
        {
            hotPathAdded = true;
        }
        else
        {
            hotPathAdded = false;
            //Debug.LogErrorFormat("Wwise:不存在此WwiseAddBasePath音频路径 {0}", _newPath);
        }
    }

    #region Play
    public void Play(string f_Event, string f_Bnk,GameObject emitterGO, int wwiseFlag,Action action = null)
    {
        WwiseFlagEnum _wwiseFlag = (WwiseFlagEnum)wwiseFlag;

        //加载 SoundBank
        if(!string.IsNullOrEmpty(f_Bnk))
        {
            string[] _bankArr = f_Bnk.Split(';');
            foreach (string bankName in _bankArr)
            {
                LoadSoundBank(bankName);
            }
        }

        //注册 RegisterGameObj
        if (emitterGO == null)
        {
            switch (_wwiseFlag)
            {
                case WwiseFlagEnum.Music:
                    emitterGO = MusicEmitter;
                    break;
                case WwiseFlagEnum.Sound:
                    emitterGO = SoundEmitter;
                    break;
                case WwiseFlagEnum.Voice:
                    emitterGO = VoiceEmitter;
                    break;
            }
        }
        else
        {
            RegisterGameObj(emitterGO);
        }

        //播放 PostEvent  
        switch (_wwiseFlag)
        {
            case WwiseFlagEnum.Music:
                uint _result = PlayMusic(f_Event, emitterGO);
                break;
            case WwiseFlagEnum.Sound:
                PlaySound(f_Event, emitterGO);
                break;
            case WwiseFlagEnum.Voice:
                PlayVoice(f_Event, emitterGO, action);
				if(action != null)
					EndOfEvent(f_Event, emitterGO, action);
                break;
        }
    }
	// 播放结束时触发回调
	public void EndOfEvent(string in_eventName, GameObject in_emitterGO, Action in_callback)
	{
		AkSoundEngine.PostEvent(in_eventName, in_emitterGO, (uint)AkCallbackType.AK_EndOfEvent, onPostEventCallbackHandle, in_callback);
	}
	private void onPostEventCallbackHandle(object in_callback, AkCallbackType in_type, AkCallbackInfo in_info)
	{
		switch (in_type)
		{
			case AkCallbackType.AK_EndOfEvent:
				if (in_callback is Action)
				{
					AkEventCallbackInfo _callbackInfo = in_info as AkEventCallbackInfo;
					(in_callback as Action)();
				}
				break;
			case AkCallbackType.AK_Marker:
				if (in_callback is Action<string>)
				{
					AkMarkerCallbackInfo _callbackInfo = in_info as AkMarkerCallbackInfo;
					Action<string> _callback = in_callback as Action<string>;
					_callback(_callbackInfo.strLabel);
				}
				break;
			case AkCallbackType.AK_Duration:
				if (in_callback is Action<float>)
				{
					AkDurationCallbackInfo _callbackInfo = in_info as AkDurationCallbackInfo;
					Action<float> _callback = in_callback as Action<float>;
					_callback(_callbackInfo.fDuration);
				}
				break;
			case AkCallbackType.AK_MusicPlaylistSelect:
				if (in_callback is Action<uint>)
				{
					AkMusicPlaylistCallbackInfo _callbackInfo = in_info as AkMusicPlaylistCallbackInfo;
					Action<uint> _callback = in_callback as Action<uint>;
					_callback(_callbackInfo.uNumPlaylistItems);
				}
				break;
			case AkCallbackType.AK_MusicSyncBeat:
				if (in_callback is Action)
				{
					AkMusicSyncCallbackInfo _callbackInfo = in_info as AkMusicSyncCallbackInfo;
					Action _callback = in_callback as Action;
					_callback();
				}
				break;
			case AkCallbackType.AK_MusicSyncBar:
				if (in_callback is Action)
				{
					AkMusicSyncCallbackInfo _callbackInfo = in_info as AkMusicSyncCallbackInfo;
					Action _callback = in_callback as Action;
					_callback();
				}
				break;
			case AkCallbackType.AK_MusicSyncUserCue:
				if (in_callback is Action)
				{
					AkMusicSyncCallbackInfo _callbackInfo = in_info as AkMusicSyncCallbackInfo;
					Action _callback = in_callback as Action;
					_callback();
				}
				break;
		}
	}

	public void SetVolume(int volume,int wwiseFlag)
    {
        WwiseFlagEnum _wwiseFlag = (WwiseFlagEnum)wwiseFlag;
        switch (_wwiseFlag)
        {
            case WwiseFlagEnum.Music:
                volume = Mathf.Clamp(volume, 0, 100);
                WwiseBehavior.SetRTPCValue("bus_mus_vol", volume);
                break;
            case WwiseFlagEnum.Sound:
                volume = Mathf.Clamp(volume, 0, 100);
                WwiseBehavior.SetRTPCValue("bus_sfx_vol", volume);
                break;
            case WwiseFlagEnum.Voice:
                volume = Mathf.Clamp(volume, 0, 100);
                WwiseBehavior.SetRTPCValue("bus_vo_vol", volume);
                break;
        }
    }

    public void LoadSoundBank(string bankName)
    {
        if (!string.IsNullOrEmpty(bankName) && !loadBankList.Contains(bankName))
        {
            //加载SoundBank
            AkBankManager.LoadBank(bankName, false, false);
            loadBankList.Add(bankName);
        }
    }
    public void LoadBankAsync(string soundBankName,LuaFunction luaFunc)
    {
        if (!string.IsNullOrEmpty(soundBankName))
        {
            if(loadBankList.Contains(soundBankName))
            {
                if (luaFunc is LuaFunction)
                {
                    luaFunc.Call();
                    luaFunc = null;
                }
            }
            else
            {
                loadBankLuaCallback = luaFunc;
                AkBankManager.LoadBankAsync(soundBankName, loadSoundBankCallback);
                loadBankList.Add(soundBankName);
            }
        }
    }

    private void loadSoundBankCallback(uint in_bankID, IntPtr in_InMemoryBankPtr, AKRESULT in_eLoadResult, uint in_memPoolId, object in_Cookie)
    {
        if(in_eLoadResult == AKRESULT.AK_Success)
        {
            if (loadBankLuaCallback is LuaFunction)
            {
                loadBankLuaCallback.Call();
                loadBankLuaCallback = null;
            }
        }
        else
        {
            Util.LogError("加载语言包出错，in_eLoadResult "+ in_eLoadResult);
        }
        
    }

    public void UnLoadSoundBank(string bankName)
    {
        AkBankManager.UnloadBank(bankName);
        if (loadBankList.Contains(bankName))
        {
            loadBankList.Remove(bankName);
        }
    }
    public void ClearAllLoadBankList()
    {
        foreach (string bankName in loadBankList)
        {
            AkBankManager.UnloadBank(bankName);
        }
        loadBankList.Clear();
    }

    public void RegisterGameObj(GameObject emitterGO)
    {
        if (!registerGameObjList.Contains(emitterGO.GetInstanceID()))
        {
            AkSoundEngine.RegisterGameObj(emitterGO);
            registerGameObjList.Add(emitterGO.GetInstanceID());
        }
    }
    public void UnregisterGameObj(GameObject emitterGO)
    {
        AkSoundEngine.UnregisterGameObj(emitterGO);
        if (registerGameObjList.Contains(emitterGO.GetInstanceID()))
        {
            registerGameObjList.Remove(emitterGO.GetInstanceID());
        }
    }
    private void ClearAllRegisterGameObjList()
    {
        registerGameObjList.Clear();
    }
    #endregion


    #region 音乐
    public uint PlayMusic(string eventName, GameObject emitterGO)
    {
        if (!string.IsNullOrEmpty(eventName))
        {
            return AkSoundEngine.PostEvent(eventName, emitterGO, (uint)WwiseFlagEnum.Music, postEventCallback, null);
        }
        return 0;
    }

    
    #endregion


    #region 音效
    public uint PlaySound(string eventName, GameObject emitterGO)
    {
        return AkSoundEngine.PostEvent(eventName, emitterGO, (uint)WwiseFlagEnum.Music, postEventCallback, null);
    }
    #endregion


    #region 语音
    private string lastVoiceEventName = "";
    public uint PlayVoice(string eventName, GameObject emitterGO = null, Action action = null)
    {
        object _cookie = null;
        // 升级语音需要有间隔
        if(eventName.Contains("_levelup"))
        {
            //将stop升级事件也转换成play 进行比较
            string _voiceEventName = eventName.Replace("Stop", "Play");
            if (lastVoiceEventName == _voiceEventName)
            {
                return 0;
            }
            lastVoiceEventName = eventName;
            _cookie = eventName;
        }
        else if(action != null)
        {
            //_cookie = action;
        }
         
        return AkSoundEngine.PostEvent(eventName, emitterGO, (uint)WwiseFlagEnum.Voice, postVoiceEventCallback, _cookie);
    }
    //执行Wwise后回调
    private void postVoiceEventCallback(object cookie, AkCallbackType type, AkCallbackInfo info)
    {
        if(cookie is string)
        {
            if ((string)cookie == lastVoiceEventName)
            {
                if (lastVoiceEventName.Contains("_levelup"))
                    Invoke("delayLevelUp", 1.5f);
            }
        }
        else if(cookie is LuaFunction)
        {
            (cookie as LuaFunction).Call();
        }
    }

    private void delayLevelUp()
    {
        lastVoiceEventName = "";
    }
    #endregion
}
